package hc.j2me;

import hc.core.ContextManager;
import hc.core.EventCenter;
import hc.core.IConstant;
import hc.core.IContext;
import hc.core.IEventHCListener;
import hc.core.IPNGScreen;
import hc.core.IScreen;
import hc.core.IScreenClient;
import hc.core.L;
import hc.core.MsgBuilder;
import hc.core.data.DataClientAgent;
import hc.core.data.DataInputEvent;
import hc.core.data.DataPNG;
import hc.core.data.DataScrBlcOp;
import hc.core.util.ByteUtil;
import hc.core.util.LogManager;
import hc.j2me.ui.PNGGameCanvas;
import hc.j2me.ui.UIManager;


public class ScreenClientManager {
	public static int remote_screen_width, remote_screen_height;
	private static int this_screen_width, this_screen_height;
	private static String clientLang;
	private static final Boolean LOCK = new Boolean(false);
	
	//仿真远程服务器的屏尺寸，与ScreenCapturer逻辑相同
//	private static int HCCtrlBackup_LocX, HCCtrlBackup_LocY;
	
	private static IScreenClient clientInstance;
	private static PNGGameCanvas pngScreen;
		
	public final static void setScreenClient(Object client){
		if(client instanceof IScreenClient){
			clientInstance = (IScreenClient)client;
		}
		
		if(client instanceof PNGGameCanvas){
			pngScreen = (PNGGameCanvas)client;
		}
	}
	
	public final static IScreenClient getScreenClient(){
		return clientInstance;
	}
	
	private static boolean isTouchScreen = false;
	private static boolean isSupportGPS = false;
	
	public static boolean isTouchScreen() {
		return isTouchScreen;
	}

	public static void setTouchScreen(boolean isTouchScreen) {
		ScreenClientManager.isTouchScreen = isTouchScreen;
	}

	public static boolean isSupportGPS() {
		return isSupportGPS;
	}

	public static void setSupportGPS(boolean isSupportGPS) {
		ScreenClientManager.isSupportGPS = isSupportGPS;
	}

	public static int getMobilePosX(int locX, int v_w){
//		if(locX == 0){
//			return 0;
//		}
		return locX * v_w / remote_screen_width; 
	}
	
	public static int getMobilePosY(int locY, int v_h){
//		if(locY == 0){
//			return 0;
//		}
		return locY * v_h / remote_screen_height;
	}
	
	public static void setClientWH(int width, int height){
		this_screen_width = width;
		this_screen_height = height;
	}
	
	public static int getClientWidth(){
		return this_screen_width;
	}
	
	public static int getClientHeight(){
		return this_screen_height;
	}
	
	public static void refreshRect(int x, int y) {
		final byte[] rectBytes = new byte[DataClientAgent.STRUCT_LEN + MsgBuilder.INDEX_MSG_DATA];
		
		pngScreen.locX = x;
		pngScreen.locY = y;
		
		//开始远程，通知SET_RECT，服务器将回应Remote_SIZE
		DataClientAgent ss = new DataClientAgent();
		ss.setBytes(rectBytes);
		
		ss.setWidth(x);
		ss.setHeight(y);
		ContextManager.getContextInstance().send(
				MsgBuilder.E_SCREEN_REFRESH_RECTANGLE, rectBytes, ss.getLength());
	}
	
	private static byte[] setTwoByteValue(final byte[] twobytes, final int pixel) {
		ByteUtil.integerToTwoBytes(pixel, twobytes, MsgBuilder.INDEX_MSG_DATA);
		return twobytes;
	}

	/**
	 * 返回0表示不可移动，
	 * 返回实际允许移动的像素量
	 * @param pixle 正数表示可以向上移，负值可以向下移
	 * @return
	 */
	public static int checkMoveUp(int locY, int pixle){
		if(remote_screen_width == 0){
			return 0;
		}

		int newLocY = locY - pixle;
		if(newLocY <= 0){
			if(locY ==0){
				return 0;
			}else{
				return locY;
			}
		}else if(newLocY >= pngScreen.BOTTOM_Y){
			if(locY == pngScreen.BOTTOM_Y){
				return 0;
			}else{
				return locY - pngScreen.BOTTOM_Y;
			}
		}else{
			return pixle;
		}
	}
	
	/**
	 * 返回0表示不可移动，正数表示可以向右移，负值可以向左移
	 * @param pixle
	 * @return
	 */
	public static int checkMoveRight(int locX, int pixle){
		if(remote_screen_width == 0){
			return 0;
		}
		
		int newLocX = locX + pixle;
		if(newLocX <= 0){
			if(locX == 0){
				return 0;
			}else{
				return -locX;
			}
		}else if(newLocX >= pngScreen.MAX_RIGHT_X){
			if(locX == pngScreen.MAX_RIGHT_X){
				return 0;
			}else{
				return pngScreen.MAX_RIGHT_X - locX;
			}
		}else{
			return pixle;
		}
	}
    
	static final byte[] moveUpTwoBytes = new byte[2 + MsgBuilder.INDEX_MSG_DATA];
	
	/**
	 * 如果返回true，则表示有效移动；否则表示已到边际或无需移屏
	 * @param pixel 正数表示可以向上移，负值可以向下移
	 * @return
	 */
	public static boolean moveUp(int pixel){
//		System.out.println("Move Up:" + pixel);
		int pixelOld = pixel;
		synchronized (LOCK) {
			pixel = checkMoveUp(pngScreen.locY, pixel);
			if(pixel == 0){
				clientInstance.noMoveWarn();
				return false;
			}
			pngScreen.locY -= pixel;
			if(pixel > 0){
				ContextManager.getContextInstance().send(
						MsgBuilder.E_SCREEN_MOVE_UP, setTwoByteValue(moveUpTwoBytes, pixel), 2);
	
				clientInstance.succMoveUp(pixel);
				
				clientInstance.copyArea(0, 0, this_screen_width, this_screen_height - pixel, 0, pixel);
			}else{
				ContextManager.getContextInstance().send(
						MsgBuilder.E_SCREEN_MOVE_DOWN, setTwoByteValue(moveUpTwoBytes, pixel * (-1)), 2);		
	
				clientInstance.succMoveUp(pixel);
				
				clientInstance.copyArea(0, -pixel, this_screen_width, this_screen_height + pixel, 0, pixel);
			}
		}
		clientInstance.refreshScreen(true);
		if(pixel > 0){
			if(pixelOld != pixel){
				clientInstance.enableMoveUp(false);
			}else{
				clientInstance.enableMoveDown(true);
			}
		}else{
			if(pixelOld != pixel){
				clientInstance.enableMoveDown(false);
			}else{
				clientInstance.enableMoveUp(true);
			}
		}
		return true;
	}

	static final byte[] moveRightTwoBytes = new byte[2 + MsgBuilder.INDEX_MSG_DATA];
	
	/**
	 * 如果返回true，则表示有效移动；否则表示已到边际或无需移屏
	 * @param pixel 正数表示可以向右移，负值可以向左移
	 */
	public static boolean moveRight(int pixel){
//		System.out.println("Move Right:" + pixel);
		
		int pixelOld = pixel;
		synchronized (LOCK) {
			pixel = checkMoveRight(pngScreen.locX, pixel);
			if(pixel == 0){
				clientInstance.noMoveWarn();
				return false;
			}
			pngScreen.locX += pixel;
			if(pixel > 0){
				ContextManager.getContextInstance().send(
						MsgBuilder.E_SCREEN_MOVE_RIGHT, setTwoByteValue(moveRightTwoBytes, pixel), 2);
				
				clientInstance.succMoveRight(pixel);
				
				clientInstance.copyArea(pixel, 0, this_screen_width - pixel, this_screen_height, -pixel, 0);
			}else{
				ContextManager.getContextInstance().send(
						MsgBuilder.E_SCREEN_MOVE_LEFT, setTwoByteValue(moveRightTwoBytes, pixel * (-1)), 2);
				
				clientInstance.succMoveRight(pixel);
				
				clientInstance.copyArea(0, 0, this_screen_width + pixel, this_screen_height, -pixel, 0);
			}
		}
		clientInstance.refreshScreen(true);
		if(pixel > 0){
			if(pixelOld != pixel){
				clientInstance.enableMoveRight(false);
			}else{
				clientInstance.enableMoveLeft(true);
			}
		}else{
			if(pixelOld != pixel){
				clientInstance.enableMoveLeft(false);
			}else{
				clientInstance.enableMoveRight(true);
			}
		}
		return true;
	}
	
	/**
	 * 中继模式下，限制最大色彩效果
	 * @param mode
	 */
	public static void setColorMode(final byte[] twobytes, final int mode){
		ContextManager.getContextInstance().send(
				MsgBuilder.E_SCREEN_COLOR_MODE, setTwoByteValue(twobytes, mode), 2);		
	}
	
	/**
	 * 中继模式下限制最大刷新频度
	 * @param millSecond
	 */
	public static void setRefreshMillSecond(int millSecond){
		final byte[] msFourBytes = new byte[4 + MsgBuilder.INDEX_MSG_DATA];
		ByteUtil.integerToFourBytes(millSecond, msFourBytes, MsgBuilder.INDEX_MSG_DATA);

		ContextManager.getContextInstance().send(
				MsgBuilder.E_SCREEN_REFRESH_MILLSECOND, msFourBytes, 4);		
	}

	static {
		remote_screen_width = 0;
		remote_screen_height = 0;
		
		if(IConstant.serverSide == false){
			EventCenter.addListener(new IEventHCListener(){
				final DataPNG dp = new DataPNG();
				final int offset = dp.png_index;
				final int maxPngDataLen = MsgBuilder.MAX_BYTE_ARRAY_LEN;
				
				public boolean action(final byte[] bs) {
					dp.setBytes(bs);
					
					int vlocX = pngScreen.locX, vlocY = pngScreen.locY;
					IPNGScreen screenSnap = pngScreen;
					
					final int pngDataLen = dp.getPNGDataLen();
					final int sameScreenIDOffset = DataPNG.png_index + pngDataLen + 1;
					final int sameScreenIDLen = bs[DataPNG.png_index + pngDataLen];//dp.getTargetIDLen(pngDataLen);
					if(screenSnap.isSameScreenID(bs, sameScreenIDOffset, sameScreenIDLen) == false){
						IScreen screen = UIManager.getDisplayableByName(bs, sameScreenIDOffset, sameScreenIDLen);
						if(screen != null && screen instanceof IPNGScreen){
							screenSnap = (IPNGScreen)screen;
							//由于遗留采用静态方法，所以本处采用简便方法
							vlocX = 0;
							vlocY = 0;
						}else{
							L.V = L.O ? false : LogManager.log("Skip over timer PNGScreen data");
							return true;
						}
					}
					
					final int history_locX = dp.getX();
					final int history_locY = dp.getY();
					final int width = dp.getWidth();
					final int height = dp.getHeight();
					final int x = history_locX - vlocX;
					final int y = history_locY - vlocY;
					
//					L.V = L.O ? false : LogManager.log("pngDataLen:" + pngDataLen + ", x : " + x + ", y:" + y + ", width:" + width + ", height:" + height);

					//增加检查条件，以防非法数据进入后期操作。注意:x可能出现负值
					if(pngDataLen > 0 && pngDataLen < maxPngDataLen && x >= -1000 && y >= 0 && width > 0 && height > 0){
						synchronized (LOCK) {
							//确保locX,locY不被其它线程并发使用
							screenSnap.drawImage(x, y, width, height, 
									bs, offset, pngDataLen);					
						}
						screenSnap.refreshScreen(false);
					}else{
						L.V = L.O ? false : LogManager.log("Skip invailid png data");
						System.out.println("pngDataLen:" + pngDataLen + ", x : " + x + ", y:" + y + ", width:" + width + ", height:" + height);
					}
					
					return true;
				}
	
				public byte getEventTag() {
					return MsgBuilder.E_IMAGE_PNG;
				}});
	
			//此逻辑要置于E_SCREEN_SET_RECTANGLE之前，因为有可能局域网测试时，先获得返回时，Lister尚未初始化
			EventCenter.addListener(new IEventHCListener(){
				public byte getEventTag() {
					return MsgBuilder.E_SCREEN_REMOTE_SIZE;
				}
				public boolean action(final byte[] bs) {
					DataClientAgent s = new DataClientAgent();
					s.setBytes(bs);
					
					remote_screen_width = s.getWidth();
					remote_screen_height = s.getHeight();
					pngScreen.locX = 0;
					pngScreen.BOTTOM_Y = remote_screen_height - this_screen_height;
					if(pngScreen.BOTTOM_Y <= 0){
						pngScreen.BOTTOM_Y = 0;
						clientInstance.enableMoveUp(false);
					}else{
						clientInstance.enableMoveUp(true);
					}
					clientInstance.enableMoveDown(false);
					pngScreen.MAX_RIGHT_X = remote_screen_width - this_screen_width;
					if(pngScreen.MAX_RIGHT_X <= 0){
						pngScreen.MAX_RIGHT_X = 0;
						clientInstance.enableMoveRight(false);
					}else{
						clientInstance.enableMoveRight(true);
					}
					clientInstance.enableMoveLeft(false);
					pngScreen.locY = pngScreen.BOTTOM_Y;
					
					clientInstance.notifyRemoteSize(remote_screen_width, remote_screen_height);
					return true;
				}});
			
			EventCenter.addListener(new IEventHCListener(){
				final DataInputEvent e = new DataInputEvent(); 
				public boolean action(final byte[] bs) {
					e.setBytes(bs);
					if(e.getType() == DataInputEvent.TYPE_TRANS_TEXT){
						try {
							clientInstance.sendBackTxtToClient(e.getTextDataAsString());
						} catch (Exception e1) {
							e1.printStackTrace();
						}
					}
					return true;
				}
	
				public byte getEventTag() {
					return MsgBuilder.E_INPUT_EVENT;
				}});
			
			EventCenter.addListener(new IEventHCListener() {
				public byte getEventTag() {
					return MsgBuilder.E_SCREEN_BLOCK_COPY;
				}
				
				final DataScrBlcOp sb = new DataScrBlcOp();
				public boolean action(final byte[] bs) {
					sb.setBytes(bs);
					clientInstance.copyArea(sb.getX(), sb.getY(), sb.getWidth(), sb.getHeight(), sb.getDX(), sb.getDY());				
					return true;
				}
			});
		}
	}

	public static String getClientLang() {
		return clientLang;
	}

	public static void setClientLang(String clientLang) {
		ScreenClientManager.clientLang = clientLang;
	}

	public static void sendClientInfo(){
		hc.core.L.V=hc.core.L.O?false:LogManager.log("Send out client desc");
		final byte[] clientInfoBS = new byte[MsgBuilder.UDP_BYTE_SIZE];
		
		DataClientAgent ss = new DataClientAgent();
		ss.setBytes(clientInfoBS);
		ss.setWidth(getClientWidth());
		ss.setHeight(getClientHeight());
		ss.setTouchScreen(isTouchScreen());
		ss.setSupportGPS(isSupportGPS());
		ss.setClientLang(getClientLang());
		String ver = (String)ContextManager.getContextInstance().doExtBiz(IContext.BIZ_VERSION_MID_OR_PC, null);
		if(ver == null){
			ver = "0.1";
		}
		ss.setVer(ver);
		
		ContextManager.getContextInstance().send(MsgBuilder.E_CLIENT_INFO, clientInfoBS, ss.getLength());
	
	}
}
